import { User, Project } from '../domain/index';
import * as _ from 'lodash';
import { createSelector } from '@ngrx/store';
import { UserActionTypes, UserActions } from '../actions/user.action';
import { ProjectActionTypes, ProjectActions } from '../actions/projects.action';

export interface State {
    ids: string[];
    entities: { [id: string]: User };
}

const initialState: State = {
    ids: [],
    entities: {}
};

const addUser = (state, action) => {
    const user = action.payload;
    // 如果存在该user 则不添加
    if (state.entities[user.id]) {
        return state;
    }
    // 如果不存在 则在 ids 中添加 user.id
    const ids = [...state.ids, user.id];
    // 在entities 中添加项目
    const entities = { ...state.entities, [user.id]: user };
    return state.entities[user.id] ? { ...state, entities } : { ...state, ids: ids, entities: entities };
};

const updateUser = (state, action) => {
    const user = <User[]>action.payload;
    const inComingEntities = _.chain(user)
        .keyBy('id')
        .mapValues(o => o)
        .value();
    const entities = { ...state, ...inComingEntities };
    return { ...state, entities };
};
const delUser = (state, action) => {
    const user = action.payload;
    const newEntities = { ...state.entities, [user.id]: user };
    return state.entities[user.id] ?
        { ...state, entities: newEntities } : state;
};
// 加载新数据， 如果存在则不添加，如果不存在则添加进去，方便进行分页
const loadUser = (state, action) => {
    const users = action.payload; // 这里返回的是个数组
    const inComingIds = users.map(p => p.id); // 获取传进来的所有id
    const newIds = _.difference(inComingIds, state.ids); // 获取两个数组的超集
    // 获取一个新的字典(对象) keyBy: 列表对象中的id 最为新对象的key 对象为值
    const inComingEntities = _.chain(users)
        .keyBy('id')
        .mapValues(o => o)
        .value();
    const newEntities = newIds.reduce((entities, id: string) => ({ ...entities, [id]: inComingEntities[id] }), {});
    return {
        ids: [...state.ids, ...newIds],
        entities: { ...state.entities, ...newEntities }
    };
};

export function reducer(state = initialState, action: UserActions | ProjectActions): State {
    switch (action.type) {
        case UserActionTypes.ADD_SUCCESS: {
            return addUser(state, action);
        }
        case UserActionTypes.DELETE_SUCCESS: {
            return delUser(state, action);
        }
        case UserActionTypes.UPDATE_SUCCESS: {
            return updateUser(state, action);
        }
        case UserActionTypes.SEARCH:
        case UserActionTypes.LOAD_SUCCESS: {
            return loadUser(state, action);
        }
        default: {
            return state;
        }
    }
}

export const getIds = (state: State) => state.ids;
export const getEntities = (state: State) => state.entities;

export const getUsers = createSelector(getIds, getEntities, (ids, entities) => {
    return ids.map(key => entities[key]);
});
